package gang.org.springframework.framework.support;

import gang.org.springframework.framework.beanfactorypostprocessor.GangBeanDefinitionRegistryPostProcessor;
import gang.org.springframework.framework.beanfactorypostprocessor.GangBeanFactoryPostProcessor;
import gang.org.springframework.framework.beanfactorypostprocessor.GangConfigurationClassPostProcessor;
import gang.org.springframework.framework.beanpostprocessor.GangBeanPostProcessor;
import gang.org.springframework.framework.beanpostprocessor.GangMergedBeanDefinitionPostProcessor;
import gang.org.springframework.framework.context.GangAbstractApplicationContext;
import gang.org.springframework.framework.factory.GangAbstractBeanFactory;
import gang.org.springframework.framework.factory.GangConfigurableListableBeanFactory;

import java.util.*;

/**
 * 明细说明参照：https://www.freesion.com/article/9580404597/
 * @author gang.chen
 * @since 2021/6/15 12:30
 */
public final class GangPostProcessorRegistrationDelegate {

    /**
     * @param beanFactory {@link gang.org.springframework.framework.factory.GangDefaultListableBeanFactory}
     * */
    public static void invokeBeanFactoryPostProcessors(GangConfigurableListableBeanFactory beanFactory, List<GangBeanFactoryPostProcessor> beanFactoryPostProcessors)
    {

        Set<String> processedBeans= new HashSet<>();


        if(beanFactory instanceof GangBeanDefinitionRegistry){

            List<GangBeanDefinitionRegistryPostProcessor> registryPostProcessors = new ArrayList<>();


            GangBeanDefinitionRegistry registry = (GangBeanDefinitionRegistry) beanFactory;
            List<GangBeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

            // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.

            String[] postProcessorNames = beanFactory.getBeanNamesForType(GangBeanDefinitionRegistryPostProcessor.class,true,false);
            for (String postProcessorName : postProcessorNames) {
                GangBeanDefinitionRegistryPostProcessor beanFactoryPostProcessor = beanFactory.getBean(postProcessorName, GangBeanDefinitionRegistryPostProcessor.class);
                currentRegistryProcessors.add(beanFactoryPostProcessor);
                //有继承关系的BeanFactoryPostProcessor执行一次即可
                processedBeans.add(postProcessorName);
            }
            registryPostProcessors.addAll(currentRegistryProcessors);
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors,registry,null);


            // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.



            // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.


            //TODO
            invokeBeanFactoryPostProcessors(registryPostProcessors,beanFactory);
        }else {
            //TODO
        }


        ArrayList<String> nonOrderedProcessorNames = new ArrayList<>();
        String[] beanFactoryPostProcessorNames = beanFactory.getBeanNamesForType(GangBeanFactoryPostProcessor.class, true, false);
        for (String ppName : beanFactoryPostProcessorNames) {
            if (processedBeans.contains(ppName)) {
                //SKIP
            }
            else if (false){
                //TODO
            }
            else if (false){
                //TODO
            }
            else {
                nonOrderedProcessorNames.add(ppName);
            }
        }
        //First, invoke the BeanFactoryPostProcessors that implements PriorityOrdered

        //Nest, invoke the BeanFactoryPostProcessors that implemtns Ordered

        //Finally, invoke all others BeanFactoryPostProcessors
        ArrayList<GangBeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedProcessorNames.size());
        for (String postProcessorName : nonOrderedProcessorNames) {
            nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, GangBeanFactoryPostProcessor.class));
        }
        invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
    }

    /**
     * @param postProcessors any instances which impl GangBeanDefinitionRegistryPostProcessor interface
     *                       reference to {@link GangBeanDefinitionRegistryPostProcessor}
     *
     * @param registry {@link gang.org.springframework.framework.factory.GangDefaultListableBeanFactory}
     * */
    private static void invokeBeanDefinitionRegistryPostProcessors(Collection<GangBeanDefinitionRegistryPostProcessor> postProcessors, GangBeanDefinitionRegistry registry, Object applicationStartup)
    {
        for (GangBeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
            postProcessor.postProcessBeanDefinitionRegistry(registry);
        }
    }

    private static void invokeBeanFactoryPostProcessors(Collection<? extends GangBeanFactoryPostProcessor> postProcessors, GangConfigurableListableBeanFactory beanFactory){
        for (GangBeanFactoryPostProcessor postProcessor : postProcessors) {
            postProcessor.postProcessBeanFactory(beanFactory);
        }
    }

    /**
     * TODO
     * @param beanFactory  {@link gang.org.springframework.framework.factory.GangDefaultListableBeanFactory}
     * @param applicationContext {@link gang.org.springframework.boot.context.GangAnnotationConfigServletWebServerApplicationContext}
     * */
    public static void registerBeanPostProcessors(
            GangConfigurableListableBeanFactory beanFactory,
            GangAbstractApplicationContext applicationContext){

        /*
         * 业务意义
         * 1）获取所有实现BeanPostProcessor接口的类
         * */

        String[] postProcessorNames = beanFactory.getBeanNamesForType(GangBeanPostProcessor.class, true, false);

        List<GangBeanPostProcessor> internalPostProcessors = new ArrayList<>();

        //TODO
        for (String ppName : postProcessorNames) {

            GangBeanPostProcessor pp = beanFactory.getBean(ppName, GangBeanPostProcessor.class);

            if (pp instanceof GangMergedBeanDefinitionPostProcessor) {


                internalPostProcessors.add(pp);
            }
        }
        /*
         * 业务处理声明
         * 场景一 处理最高优化级的BeanPostProcessor，其实现了PriorityOrdered接口
         * */


        /**
         * 业务处理声明
         * 场景二 处理第二优先级的BeanPostProcessor，其实现了Ordered接口
         * */

        /**
         * 业务处理声明
         * 场景三 处理最低优先级的BeanPostProcessor，未实现排序接口
         * */
        sortPostProcessors(internalPostProcessors, beanFactory);
        registerBeanPostProcessors(beanFactory, internalPostProcessors);
    }

    private static void sortPostProcessors(List<?> postProcessors, GangConfigurableListableBeanFactory beanFactory){
        //TODO
    }

    private static void  registerBeanPostProcessors(GangConfigurableListableBeanFactory beanFactory,
                                                    List<GangBeanPostProcessor> postProcessors){
        //TODO
        if (beanFactory instanceof GangAbstractBeanFactory) {
            ((GangAbstractBeanFactory)beanFactory).addBeanPostProcessors(postProcessors);
        }

    }
}
